home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Simple Slideshow / MacZapp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-24  |  15.4 KB  |  550 lines  |  [TEXT/MPCC]

  1. /*************************************************************************************************
  2. *
  3. *
  4. *            MacZapp        -- a standard Mac application template
  5. *
  6. *
  7. *************************************************************************************************/
  8.  
  9. /* This is a comment- comments are delimited by slash-star to start and star-slash to end: */
  10. // alternatively, a comment on a single line can start with two slashes- it doesn't need
  11. // to be terminated, but each line needs the comment delimiter if you use this style.
  12.  
  13. // The first line of actual code should include any header files that this code requires. The
  14. // toolbox headers "MacHeaders" are automatically included by THINK C, etc. Note that any
  15. // statement beginning with # is a COMPILER DIRECTIVE- it is an instruction to the compiler, not
  16. // to the computer.
  17.  
  18. // This line includes a header file which has the function prototypes. These are needed so that
  19. // the compiler can tell what parameters to pass to functions, and to chack the syntax of function
  20. // calls
  21.  
  22.  
  23. #include    "Prototypes.h"
  24. #include    "Palettes.h"
  25. #include    "Gestalt.h"
  26. #include     "ShowHideMenubar.h"
  27.  
  28. //#include    "DialogUtils.h"
  29.  
  30. //#include    "NewSneakyJump.c"
  31. //#include    "CoolSliderCDEF.h"
  32.  
  33.  
  34. // you can declare a constant byy using the #define statement. This works like Pascal's CONST
  35. // keyword. It is good style to use symbolic constants wherever possible rather than hard coding
  36. // numerical values- it makes the code easier to understand (by a human!). Furthermore, a good
  37. // convention is to begin all constants with the letter k, all globals with the letter g, to
  38. // use names starting with a lowercase letter for local variables, and names starting with an 
  39. // uppercase letter for function names. This is only a convention- you don't HAVE to do this, but
  40. // if you are consistent, you'll find it much easier to write readable code.
  41.  
  42. #define        kSleepTime            10        // number of ticks to give up to background programs
  43. #define        kUntitledWindowID    128        // resource ID of the main window template
  44. #define        kMenuBarID            128        // resource ID of the MBAR resource
  45. #define        kAppleMenuID        128        // ID of the apple menu
  46.  
  47. // a note about resources. In THINK C and similar, if you create a ResEdit file which has the
  48. // same name as the PROJECT, appended with .rsrc, this file will automatically opened when you
  49. // run the application in the development environment. This file must be in the same folder as
  50. // the project file. You can put all your resources in this file- the compiler will copy them
  51. // into the application when you finally build it
  52.  
  53. // next, declare any global variables you want. This is like pascals VAR statement, except that C
  54. // understands that any name left 'naked' is a variable by default
  55.  
  56. Boolean        gDone;                        // if you set this to TRUE, the app will quit
  57. short        gSleepTime;                    // this is the current number of sleep ticks
  58. FSSpec        gSlideFolder;                // the filespec for the source image folder
  59. Boolean        gFolderChosen;                // true if a folder has been selected
  60. WindowPtr    gSlideWindow;                // the window to display them in    
  61. MenuHandle    gFileMenu;
  62.  
  63. extern long        gSlideTicks;
  64. extern long        gLastTicks;
  65. extern short    gSlideIndex;
  66. extern short    gSlidePhase;
  67. extern    PicHandle    gPicture;
  68. extern Boolean    gHideMBar;
  69. extern Boolean    gAutoRun;
  70.  
  71. // now for the code! Evey C program must have one and only one entry point, called main. Here
  72. // it is:
  73.  
  74. void    main()
  75. {
  76.     // this is the main program, in its entirety:
  77.  
  78.     InitialiseTheApp();
  79.     RunTheApp();
  80.     QuitTheApp();
  81. }
  82.  
  83. // the form of a function is always the same. There is no distinction between FUNCTIONS and 
  84. // PROCEDURES, as there is in Pascal. Everything is a function, though by using the VOID keyword,
  85. // is can return nothing, and so is equivalent to a procedure. Every function must have a
  86. // parameter list, though this may be empty. i.e. AFunction() is valid, AFunction is not. (it must
  87. // have brackets following the name).
  88.  
  89. // There is no BEGIN and END statement, instead, the { and } brackets serve the same function.
  90. // all program statements must be terminated by a semi-colon.
  91.  
  92. // here are the procedures that main calls:
  93.  
  94. void    InitialiseTheApp()
  95. {
  96.     // normally you would put a comment here explaining what the function does. This one starts
  97.     // up the application, installing the menubar and opening the untitled window
  98.     
  99.     Handle        theMenuBar;
  100.     MenuHandle    theAppleMenu;
  101.  
  102.     // every mac application starts up with the same 'mantra' which must be chanted exactly as
  103.     // given here to persuade the mac spirits to smile favourably on your program...
  104.     
  105.     InitGraf(&qd.thePort);
  106.     InitFonts();
  107.     InitWindows();
  108.     InitMenus();
  109.     TEInit();
  110.     InitDialogs(NULL);
  111.     
  112.     // now you should clear out the event queue in case any stray clicks or keypresses are left
  113.     // there
  114.     
  115.     FlushEvents(everyEvent,0);
  116.  
  117.     // now give yourself enough memory. For a bigger app, you may need to call MoreMasters a few
  118.     // more times
  119.     
  120.     MaxApplZone();
  121.     MoreMasters();
  122.     
  123.     // see if the program can run on this Mac- if not, we show an alert and exit
  124.     
  125.     CheckCanRun();    
  126.     
  127.     // now we can install our menu bar. We use an MBAR resource to list the actual menus. This
  128.     // makes it easier to add menus just by editing the resources.
  129.     
  130.     theMenuBar = GetNewMBar(kMenuBarID);
  131.     
  132.     if(theMenuBar)
  133.     {
  134.         SetMenuBar(theMenuBar);
  135.         ReleaseResource(theMenuBar);
  136.         
  137.         // now fill the apple menu with a list of all the apple menu items. This is done as
  138.         // follows. This appears a bit odd, once you know what this means, but the reasons
  139.         // for it have to do with the way System 1 worked, so just take my word for it...
  140.         
  141.         theAppleMenu = GetMHandle(kAppleMenuID);
  142.         
  143.         if (theAppleMenu)
  144.             AddResMenu(theAppleMenu,'DRVR');
  145.     }
  146.     
  147.     gFileMenu = GetMHandle(kFileMenu);
  148.     
  149.     // OK, we have installed the menu bar, now we draw it, which displays the titles
  150.     
  151.     DrawMenuBar();
  152.     
  153.     // set up the application globals
  154.     
  155.     gDone = FALSE;                    // we're not quitting yet
  156.     gSleepTime = kSleepTime;        // set the sleep period
  157.     
  158.     InitCursor();                    // set the cursor to the arrow and make it visible
  159.     
  160.     
  161.     gSlideTicks = 300;                // 5 seconds, but overriden by prefs
  162.     gLastTicks = TickCount();
  163.     gSlideIndex = 0;
  164.     gFolderChosen = FALSE;
  165.     gSlidePhase = 0;
  166.     
  167.     // ready to go, so open a default window
  168.     
  169.     RestorePrefs();
  170.     OpenNewWindow(kUntitledWindowID);
  171.     if (gFolderChosen && gAutoRun)
  172.         StartSlideshow();    
  173.     else    
  174.         StopSlideshow();
  175. }
  176.  
  177.  
  178.  
  179. void    RunTheApp()
  180. {
  181.     // this function loops round, pulling events off the queue as long as the user hasn't quit.
  182.     // The events arrive in any order, and the app just handles them one after another
  183.     
  184.     EventRecord        theEvent;        // this record is the current event
  185.     
  186.     while (! gDone)
  187.     {
  188.         if (WaitNextEvent(everyEvent,&theEvent,gSleepTime,NULL))
  189.         {
  190.             // we obtained an event, now handle it
  191.             
  192.             HandleTheEvent(&theEvent);
  193.         }
  194.         else
  195.             RunSlideshow();    // show the slides while null events arrive
  196.     }
  197. }
  198.  
  199.  
  200. void    QuitTheApp()
  201. {
  202.     // here you would do any cleanup during the quitting phase of the application. In this case
  203.     // we do nothing, so this is an empty function or "stub"
  204.     
  205.     SetMBarState(SHOW);
  206.     RestoreDeviceClut(NULL);
  207.     SavePrefs();
  208. }
  209.  
  210.  
  211. // The next most important function is the event handler. This determines the type of event that
  212. // occurred, and dispatches it to the various routines needed to process them
  213.  
  214. void    HandleTheEvent(EventRecord *theEvent)
  215. {
  216.     WindowPtr        targWindow;        // the window the event was aimed at
  217.     char            keyChar;        // the ascii code of a key that was pressed
  218.     long            mSelect;        // menu and item chosen, if any
  219.         
  220.     switch (theEvent->what)
  221.     {
  222.         case mouseDown:
  223.             // the mouse was clicked somewhere- pass it on
  224.             HandleMouseEvent(theEvent);
  225.             break;
  226.         case updateEvt:
  227.             // a window needs refreshing, find out which and do it
  228.             
  229.             targWindow = (WindowPtr) theEvent->message;
  230.             SetPort(targWindow);
  231.             BeginUpdate(targWindow);
  232.             
  233.             // an update event is telling us to refresh the window, so we call our
  234.             // drawing function for the window
  235.             
  236.             DrawTheWindow(targWindow);
  237.             EndUpdate(targWindow);
  238.             break;
  239.         case keyDown:
  240.             // a key was pressed on the keyboard, if it was together with the command key,
  241.             // then it is considered as a menu key shortcut, so look it up and dispatch it
  242.             // as if the selection came from the menu in the first place
  243.             
  244.             keyChar = theEvent->message & charCodeMask;
  245.             if ((theEvent->modifiers & cmdKey) == cmdKey)
  246.             {
  247.                 mSelect = MenuKey(keyChar);
  248.                 HandleMenuSelection(mSelect);
  249.             }
  250.             else
  251.                 HandleKeypress(FrontWindow(),keyChar);
  252.             break;
  253.         case autoKey:
  254.             // a key is held down on the keyboard. This shouldn't be a menu command, so just pass
  255.             // it on
  256.             
  257.             keyChar = theEvent->message & charCodeMask;
  258.             HandleKeypress(FrontWindow(),keyChar);
  259.             break;
  260.         case osEvt:
  261.         case activateEvt:
  262.         case diskEvt:
  263.         default:
  264.             // other event types are ignored in this simple example
  265.             break;
  266.     }
  267. }
  268.  
  269.  
  270. #define    kMinWindowWidth        60
  271. #define    kMinWindowHeight    40
  272.  
  273.  
  274. void    HandleMouseEvent(EventRecord *theEvent)
  275. {
  276.     // the mouse went down somewhere. This function finds out where and dispatches that click to
  277.     // the appropriate place
  278.     
  279.     short        mouseTarget;                // a code for what the mouse actually hit
  280.     WindowPtr    targWindow;                    // if it clicked in a window, this is the one
  281.     Rect        dragBounds,growBounds;        // rectangles for controlling window drags etc.
  282.     long        mSelect;                    // menu info if a menu was pulled down
  283.     long        growthFactor;                // new size of a window after a grow
  284.     
  285.     // in case we're going to do a window drag, set up the rect for constraining it
  286.     
  287.     dragBounds = (*GetGrayRgn())->rgnBBox;
  288.     InsetRect(&dragBounds,4,4);
  289.     
  290.     // determine which part of the screen was clicked
  291.     
  292.     mouseTarget = FindWindow(theEvent->where,&targWindow);
  293.     
  294.     switch (mouseTarget)
  295.     {
  296.         case inMenuBar:
  297.             // mouse was clicked in the menubar- pull down the menu and track it
  298.             
  299.             mSelect = MenuSelect(theEvent->where);
  300.             HandleMenuSelection(mSelect);
  301.             break;
  302.         case inDrag:
  303.             // the mouse is in drag (dressed as a woman) so move the window
  304.             
  305.             DragWindow(targWindow,theEvent->where,&dragBounds);
  306.             break;
  307.         case inGrow:
  308.             // the mouse is in the grow box of a resizeable window, so drag the outline and
  309.             // resize the window if the user wants that. growBounds constrains the size
  310.             // to a certain largest and certain smallest size
  311.             
  312.             SetRect(&growBounds,kMinWindowWidth,kMinWindowHeight,dragBounds.right,dragBounds.bottom);
  313.             
  314.             growthFactor = GrowWindow(targWindow,theEvent->where,&growBounds);
  315.             if (growthFactor)
  316.                 SizeWindow(targWindow,LoWord(growthFactor),HiWord(growthFactor),TRUE);
  317.             
  318.             break;
  319.         case inGoAway:
  320.             // the mouse was clicked in the close box of a window- track it and if the user actually
  321.             // clicked it, then get rid of the window altogether
  322.             
  323.             if (TrackGoAway(targWindow,theEvent->where))
  324.                 DisposeWindow(targWindow);
  325.                 
  326.             break;
  327.         case inZoomIn:
  328.         case inZoomOut:
  329.             // the mouse was clicked in the zoom box of a zoomable window- track it, and then zoom the
  330.             // window appropriately
  331.             
  332.             if (TrackBox(targWindow,theEvent->where,mouseTarget))
  333.             {
  334.                 SetPort(targWindow);
  335.                 EraseRect(&targWindow->portRect);
  336.                 ZoomWindow(targWindow,mouseTarget,TRUE);
  337.             }
  338.             break;
  339.         case inSysWindow:
  340.             // the mouse was clicked in a desk accessory window- just pass it to the system to deal with
  341.             SystemClick(theEvent,targWindow);
  342.             break;
  343.         case inContent:
  344.             // the mouse was clicked in the main area of the users window. If the window is not in front, then
  345.             // it should be brought to the front. If it is already in front, pass the click to the window
  346.             
  347.             if (targWindow == FrontWindow())
  348.                 ClickTheWindow(targWindow,theEvent->where);
  349.             else
  350.                 SelectWindow(targWindow);
  351.                 
  352.             break;
  353.         default:
  354.             break;
  355.     }
  356. }
  357.  
  358.  
  359. //#define        kFileMenu        129
  360. #define        kEditMenu        130
  361. #define        kShowAboutBox    1
  362. #define        kAboutBoxID        128
  363.  
  364.  
  365. void    HandleMenuSelection(long mSelect)
  366. {
  367.     // this function dispatches chosen menu commands. Only the very basic ones are handled here- you will need
  368.     // to extend this function to implement other menu commands. The defines above indicate the menu layout
  369.     // that is understood by this function.
  370.  
  371.     short        menuID,itemID;
  372.     Str255        daName;
  373.     GrafPtr        savePort;
  374.     short        itemClicked;
  375.     
  376.     menuID = HiWord(mSelect);
  377.     itemID = LoWord(mSelect);
  378.     
  379.     switch(menuID)
  380.     {
  381.         case kAppleMenuID:
  382.             if (itemID == kShowAboutBox)
  383.                 //itemClicked = Alert(kAboutBoxID,NULL);
  384.                 DoAboutBox();
  385.             else
  386.             {
  387.                 // a DA was chosen, so open it
  388.                 
  389.                 GetItem(GetMHandle(menuID),itemID,daName);
  390.                 GetPort(&savePort);
  391.                 OpenDeskAcc(daName);
  392.                 SetPort(savePort);
  393.             }
  394.             break;
  395.         case kFileMenu:
  396.             switch (itemID)
  397.             {
  398.                 case kItemChooseSlides:
  399.                     gFolderChosen |= ChooseFolder(&gSlideFolder);
  400.                     if (gFolderChosen)
  401.                         StopSlideshow();;
  402.                     break;
  403.                 case kItemOptions:
  404.                     DoOptions();
  405.                     break;
  406.                 case kItemGo:
  407.                     StartSlideshow();
  408.                     break;
  409.                 case kItemStop:
  410.                     StopSlideshow();
  411.                     break;
  412.                 case kItemStartOver:
  413.                     ResetSlideshow();
  414.                     break;
  415.                 case kItemQuit:
  416.                     gDone = TRUE;
  417.                     break;
  418.                 default:
  419.                     SysBeep(1);
  420.                     break;
  421.             }
  422.             break;
  423.         case kEditMenu:
  424.             break;
  425.         default:
  426.             break;
  427.     }
  428.     HiliteMenu(0);
  429. }
  430.  
  431.  
  432. void    OpenNewWindow(short windowResID)
  433. {
  434.     // opens and displays a window using a WIND resource with the given ID
  435.     
  436.     WindowPtr        theWindow;
  437.     Rect            bounds;
  438.     
  439.     theWindow = GetNewCWindow(windowResID,NULL,(WindowPtr) -1L);
  440.     
  441.     if (theWindow)
  442.     {
  443.         SetSlideWindowSize(theWindow);
  444.         ShowWindow(theWindow);
  445.         SelectWindow(theWindow);
  446.         
  447.         gSlideWindow = theWindow;
  448.     }
  449. }
  450.  
  451.  
  452. void    ClickTheWindow(WindowPtr theWindow,Point clickLocation)
  453. {
  454.     // this handles clicks for the users window. This is mostly an empty function- you will need to
  455.     // modify it to make it do anything useful
  456.     
  457.     GrafPtr            savePort;
  458.     short            partCode,val;
  459.     ControlHandle    aControl;
  460.     
  461.     if (theWindow)
  462.     {
  463.         GetPort(&savePort);
  464.         SetPort(theWindow);
  465.         
  466.         // translate coordinates from global to window local
  467.         
  468.         GlobalToLocal(&clickLocation);
  469.         SetPort(savePort);
  470.         
  471.         // in this application, we allow mouse clicks to suspend slideshow
  472.         // display temporarily (i.e. hold image function). This is
  473.         // simply accomplished by waiting here for the mouse button to go up.
  474.         
  475.         while (WaitMouseUp());
  476.     }
  477. }
  478.  
  479.  
  480. void    HandleKeypress(WindowPtr theWindow,char keyChar)
  481. {
  482.     // handles keystrokes targeted at this window. This does nothing at all at present
  483. }
  484.  
  485.  
  486. /******************************************************************************
  487.  CopyPString
  488.  
  489.         Copy a Pascal string
  490.  ******************************************************************************/
  491.  
  492. void    CopyPString(
  493.     ConstStr255Param        srcString,
  494.     Str255        destString)
  495. {
  496.     BlockMove(srcString, destString, srcString[0] + 1L);
  497. }
  498.  
  499.  
  500. /******************************************************************************
  501.  ConcatPStrings
  502.  
  503.         Concatenate two Pascal strings by attaching the second string on
  504.         the end of the first string.
  505.  ******************************************************************************/
  506.  
  507. void    ConcatPStrings(
  508.     Str255        first,
  509.     ConstStr255Param second)
  510. {
  511.  
  512.     short charsToCopy;
  513.  
  514.     // Truncate if concatenated string would be longer than 255 chars.
  515.  
  516.     charsToCopy = Min(second[0], 255 - first[0]);
  517.     BlockMove(second + 1, first + first[0] + 1, (long) charsToCopy);
  518.     first[0] += charsToCopy;
  519. }
  520.  
  521.  
  522.  
  523. void    CheckCanRun()
  524. {
  525.     OSErr        theErr;
  526.     long        gestaltResult;
  527.     Boolean        mustQuit = FALSE;
  528.     
  529.     theErr = Gestalt(gestaltQuickdrawVersion,&gestaltResult);
  530.     
  531.     if (theErr || gestaltResult < gestalt32BitQD)
  532.         mustQuit = TRUE;
  533.         
  534.     theErr = Gestalt(gestaltProcessorType,&gestaltResult);
  535.     
  536.     if (theErr || gestaltResult < gestaltCPU68020)
  537.         mustQuit = TRUE;
  538.  
  539.     theErr = Gestalt(gestaltSystemVersion,&gestaltResult);
  540.     
  541.     if (theErr || gestaltResult < 0x0700)
  542.         mustQuit = TRUE;
  543.     
  544.     if (mustQuit)
  545.     {
  546.         Alert(131,NULL);
  547.         ExitToShell();
  548.     }
  549. }
  550.